import { Server as SocketIOServer, Socket } from 'socket.io';
import { Server as HttpServer } from 'http';
import { verifyToken } from '@/utils/jwt';
import { logger } from '@/utils/logger';
import { config } from '@/config';
import { prisma } from '@/config/database';

interface AuthenticatedSocket extends Socket {
  userId?: string;
  username?: string;
}

export class SocketService {
  private io: SocketIOServer;

  static instance: SocketService | null = null;

  constructor(server: HttpServer) {
    SocketService.instance = this;
    this.io = new SocketIOServer(server, {
      cors: {
        origin: config.cors.origin,
        methods: ['GET', 'POST'],
        credentials: true,
      },
    });

    this.setupMiddleware();
    this.setupEventHandlers();
  }

  private setupMiddleware() {
    // 身份验证中间件
    this.io.use((socket: any, next) => {
      try {
        const token = socket.handshake.auth.token;
        logger.info('Socket连接尝试', { socketId: socket.id, hasToken: !!token });
        
        if (!token) {
          logger.error('Socket认证失败: 缺少token', { socketId: socket.id });
          return next(new Error('Authentication error: No token provided'));
        }

        const decoded = verifyToken(token);
        socket.userId = decoded.userId;
        logger.info('Socket认证成功', { socketId: socket.id, userId: decoded.userId });
        next();
      } catch (error) {
        const errorMessage = error instanceof Error ? error.message : 'Unknown error';
        logger.error('Socket authentication error:', { socketId: socket.id, error: errorMessage });
        next(new Error('Authentication error: ' + errorMessage));
      }
    });
  }

  private setupEventHandlers() {
    this.io.on('connection', (socket: Socket) => {
      const authSocket = socket as AuthenticatedSocket;
      this.handleConnection(authSocket);
    });
  }

  private handleConnection(socket: AuthenticatedSocket) {
    logger.info(`用户连接: ${socket.userId}`);

    // 加入用户专属房间
    if (socket.userId) {
      socket.join(`user_${socket.userId}`);
      logger.info(`用户 ${socket.userId} 加入房间 user_${socket.userId}`);
    }

    socket.on('send_message', (data) => this.handleSendMessage(socket, data));
    socket.on('join_game', (data) => this.handleJoinGame(socket, data));
    socket.on('game_move', (data) => this.handleGameMove(socket, data));
    socket.on('disconnect', () => this.handleDisconnect(socket));
  }

  private handleDisconnect(socket: AuthenticatedSocket) {
    logger.info(`用户断开连接: ${socket.userId}`);
  }

  private async handleSendMessage(socket: AuthenticatedSocket, data: any) {
    try {
      const { content, type = 'text' } = data;
      const senderId = socket.userId;

      if (!senderId) {
        socket.emit('error', { message: '用户未认证' });
        return;
      }

      if (!content || content.trim() === '') {
        socket.emit('error', { message: '消息内容不能为空' });
        return;
      }

      // 获取另一个用户ID
      const otherUser = await prisma.user.findFirst({
        where: { id: { not: senderId } },
        select: { id: true }
      });

      if (!otherUser) {
        socket.emit('error', { message: '聊天对象不存在' });
        return;
      }

      // 保存消息到数据库
      const message = await prisma.message.create({
        data: {
          content: content.trim(),
          type,
          senderId,
          receiverId: otherUser.id
        },
        include: {
          sender: {
            select: {
              id: true,
              username: true,
              nickname: true,
              avatar: true
            }
          },
          receiver: {
            select: {
              id: true,
              username: true,
              nickname: true,
              avatar: true
            }
          }
        }
      });

      // 发送给发送者确认
      socket.emit('message_sent', message);

      // 发送给接收者
      socket.to(`user_${otherUser.id}`).emit('new_message', message);

      logger.info(`消息发送成功`, { messageId: message.id, senderId });
    } catch (error) {
      logger.error('发送消息失败:', error);
      socket.emit('error', { message: '发送消息失败' });
    }
  }

  private handleJoinGame(socket: AuthenticatedSocket, data: any) {
    // 实现加入游戏逻辑
    logger.info('User joined game:', data);
  }

  private handleGameMove(socket: AuthenticatedSocket, data: any) {
    // 实现游戏移动逻辑
    logger.info('Game move:', data);
  }

  public getIO(): SocketIOServer {
    return this.io;
  }
}

export default SocketService;